package com.htfyun.unisound.serialmotor.fragment;

import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.TextView;

import com.htfyun.nvrom.NVRomIntegerInfo;
import com.htfyun.nvrom.NVRomOperation;
import com.htfyun.nvrom.NVRomStringInfo;
import com.htfyun.serialport.ServoSingleton;
import com.htfyun.serialport.uartservo.IServoControl;
import com.htfyun.serialport.uartservo.OnServoListener;
import com.htfyun.serialport.uartservo.ServoControlAttr;
import com.htfyun.serialport.uartservo.ServoErrorAttr;
import com.htfyun.serialport.uartservo.ServoInterestedInfo;
import com.htfyun.unisound.serialmotor.AX12UpdateActivity;
import com.htfyun.unisound.serialmotor.DebugLog;
import com.htfyun.unisound.serialmotor.R;
import com.xw.repo.BubbleConfigBuilder;
import com.xw.repo.BubbleSeekBar;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TestPositionFragment extends BaseFragment implements
        View.OnClickListener,
        BubbleSeekBar.OnProgressChangedListener,
        OnServoListener {



    private TextView txtMovingStatus;
    private TextView txtCurrentPosition;
    private TextView txtCurrentAngularVelocity;

    private Map<SeekBarControlEnum, LayoutSeekBarViewHolder> seekBarControlEnumMap = new HashMap<>();

    private Handler handler = new Handler();
    @Override
    protected View initViews(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_pisition, container, false);

        initView(view);
        return view;
    }
    private void initView(View v) {
        txtMovingStatus = (TextView) v.findViewById(R.id.txtMovingStatus);
        txtCurrentPosition = (TextView) v.findViewById(R.id.txtCurrentPosition);
        txtCurrentAngularVelocity = (TextView) v.findViewById(R.id.txtCurrentAngularVelocity);

        updateCurrentAngularVelocity(0);
        updateCurrentPosition(0);
        updateMovingStatus(false);


        View status = v.findViewById(R.id.status);
        View stop = v.findViewById(R.id.stop);
        View setZero = v.findViewById(R.id.setZero);
        View updateServo = v.findViewById(R.id.updateServo);
        status.setOnClickListener(this);
        stop.setOnClickListener(this);
        setZero.setOnClickListener(this);
        updateServo.setOnClickListener(this);

        for (SeekBarControlEnum item : SeekBarControlEnum.values()) {
            View container = v.findViewById(item.getContainerViewRes());
            if (container == null) {
                continue;
            }
            container.setTag(item);
            seekBarControlEnumMap.put(item, new LayoutSeekBarViewHolder(container));
        }

    }

    @Override
    protected void onInvisible() {
        super.onInvisible();
        DebugLog.e("onInvisible = ");

        ServoSingleton.INSTANCE.getServoControl().unregisterServoListener(this);

    }

    @Override
    protected void onVisible() {
        super.onVisible();

        DebugLog.e("onVisible = ");

        ServoSingleton.INSTANCE.getServoControl().registerServoListener(this);

        getStatus();
    }

    private void getStatus() {
        ServoSingleton.INSTANCE.getServoControl().getAngleAreaMin();
        ServoSingleton.INSTANCE.getServoControl().getAngleAreaMax();
        ServoSingleton.INSTANCE.getServoControl().getPosition();
        ServoSingleton.INSTANCE.getServoControl().getAngularVelocity();
        ServoSingleton.INSTANCE.getServoControl().getFeedbackTime_100ms();

    }

    @Override
    public void onClick(View v) {
        DebugLog.e("View tag = " + v.getTag());

        final int id = v.getId();
        switch (id) {
            case R.id.sub:
                actionImgSubOrAdd(v, false);
                break;
            case R.id.add:
                actionImgSubOrAdd(v, true);
                break;
            case R.id.status:
                getStatus();
                break;
            case R.id.stop:
                ServoSingleton.INSTANCE.getServoControl().servoStop();
                break;
            case R.id.setZero:
                DebugLog.e("setZero click");
                ServoInterestedInfo info = ServoSingleton.INSTANCE.getServoControl().getServoInterestedInfo();
                ServoSingleton.INSTANCE.getServoControl().servoStop();
                ServoSingleton.INSTANCE.getServoControl().setZeroForServo();

                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        ServoSingleton.INSTANCE.getServoControl().getPosition();
                    }
                }, 300);
                break;
            case R.id.updateServo:
                Intent intent = new Intent(getContext(), AX12UpdateActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                getContext().startActivity(intent);
                break;

        }
    }

    @Override
    public void onProgressChanged(BubbleSeekBar bubbleSeekBar, int progress, float progressFloat, boolean fromUser) {
    }

    @Override
    public void getProgressOnActionUp(BubbleSeekBar bubbleSeekBar, int progress, float progressFloat) {
//        DebugLog.e("getProgressOnActionUp bubbleSeekBar tag = " + bubbleSeekBar.getTag());
        actionSeekBar(bubbleSeekBar, progress);
    }

    @Override
    public void getProgressOnFinally(BubbleSeekBar bubbleSeekBar, int progress, float progressFloat, boolean fromUser) {
//        DebugLog.e("getProgressOnFinally bubbleSeekBar tag = " + bubbleSeekBar.getTag());

    }

    @Override
    public void onServoListener(List<ServoErrorAttr> errorAttrList, ServoControlAttr controlAttr, ServoControlAttr.Instruction instruction, ServoInterestedInfo info) {

        if (errorAttrList != null && !errorAttrList.isEmpty()) {
            for (ServoErrorAttr errorAttr : errorAttrList) {
                DebugLog.e(" errorAttr = " + errorAttr);
            }
        }

        if (controlAttr == null) {
            DebugLog.e(" controlAttr is null");
            return;
        }

        DebugLog.e("instruction = " + instruction + ", controlAttr = " + controlAttr);

        final ServoInterestedInfo interestedInfo = info;
        final ServoControlAttr cAttr = controlAttr;

//        if (instruction == ServoControlAttr.Instruction.get)
        {
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {

                    switch (cAttr) {
                        case angle_area_min:
                            updateSeekBarWithSeekBarControlEnum(SeekBarControlEnum.minAngle, interestedInfo.getAngleAreaMin());
                            break;
                        case angle_area_max:
                            updateSeekBarWithSeekBarControlEnum(SeekBarControlEnum.maxAngle, interestedInfo.getAngleAreaMax());
                            break;
                        case angular_velocity:
                            updateCurrentAngularVelocity(interestedInfo.getAngularVelocity());
                            updateSeekBarWithSeekBarControlEnum(SeekBarControlEnum.angularVelocity, interestedInfo.getAngularVelocity());
                            break;
                        case position:
                            updateCurrentPosition(interestedInfo.getPosition());
                            updateSeekBarWithSeekBarControlEnum(SeekBarControlEnum.positionController, interestedInfo.getPosition());
                            updateMovingStatus(interestedInfo.isMoving());
                            break;
                        case move_status:
                            updateMovingStatus(interestedInfo.isMoving());
                            break;
                        case set_feedback_time:
                            updateSeekBarWithSeekBarControlEnum(SeekBarControlEnum.feedbackTime, interestedInfo.getFeedbackTime_100ms());
                            DebugLog.e("~~~~~~set_feedback_time = " + interestedInfo.getFeedbackTime_100ms());
                            break;
                    }

                }
            });
        }
    }

    private void updateSeekBarWithSeekBarControlEnum(SeekBarControlEnum controlEnum, int value) {
        if (controlEnum == null) {
            DebugLog.e(" controlEnum is null");
            return;
        }

        LayoutSeekBarViewHolder holder = seekBarControlEnumMap.get(controlEnum);
        if (holder == null) {
            DebugLog.e(" holder is null for controlEnum = " + controlEnum);
            return;
        }

        if (holder.getSeekBar() != null) {
            holder.getSeekBar().setProgress(value);
        }

        switch (controlEnum) {
            case minAngle:
            case maxAngle:
                updatePositionSeekBarMinOrMax(controlEnum == SeekBarControlEnum.minAngle, value);
                break;
        }
    }

    private void updatePositionSeekBarMinOrMax(boolean min, int value) {
        LayoutSeekBarViewHolder holder = seekBarControlEnumMap.get(SeekBarControlEnum.positionController);
        if (holder == null) {
            DebugLog.e(" holder is for positionController");
            return;
        }

        BubbleSeekBar seekBar = holder.getSeekBar();

        if (seekBar == null) {
            DebugLog.e(" holder seekbar is null");
            return;
        }

        BubbleConfigBuilder builder = seekBar.getConfigBuilder();
        if (builder == null) {
            return;
        }
        if (min) {
            builder.min(value);
        } else {
            builder.max(value);
        }

        if (builder.getSectionTextColor() == Color.RED) {
            builder.sectionTextColor(Color.BLUE);
        } else {
            builder.sectionTextColor(Color.RED);
        }
        builder.build();

    }


    private void updateMovingStatus(boolean move) {
        String status = getString(R.string.no);
        if (move) {
            status = getString(R.string.yes);
        }
        txtMovingStatus.setText(getString(R.string.status_moving, status));
    }

    private void updateCurrentPosition(int position) {
        txtCurrentPosition.setText(getString(R.string.status_current_position, position));
    }

    private void updateCurrentAngularVelocity(int velocity) {
        txtCurrentAngularVelocity.setText(getString(R.string.status_current_angular_velocity, velocity));
    }

    private void actionImgSubOrAdd(View view, boolean add) {

        if (!(view.getTag() instanceof SeekBarControlEnum)) {
            DebugLog.e("view.getTag() is not instanceof SeekBarControlEnum, view.getTag() = " + view.getTag());
        }

        SeekBarControlEnum seekBarControlEnum = (SeekBarControlEnum) view.getTag();

        LayoutSeekBarViewHolder holder = seekBarControlEnumMap.get(seekBarControlEnum);
        if (holder == null) {
            DebugLog.e(seekBarControlEnum + ", holder is null");
            return;
        }

        BubbleSeekBar seekBar = holder.getSeekBar();
        if (seekBar == null) {
            DebugLog.e(seekBarControlEnum + ", seekBar is null");
            return;
        }

        int progress = seekBar.getProgress();

        if (!add) {
            progress--;

        } else {
            progress++;
        }

        if (progress < 0) {
            DebugLog.e(seekBarControlEnum + ", invalid seekBar progress(" + progress + ")");
            return;
        }

        if (progress > seekBar.getMax()) {
            DebugLog.e(seekBarControlEnum + ", invalid seekBar progress(" + progress + "), max is " + seekBar.getMax());
            return;
        }

        seekBar.setProgress(progress);

        sendServoValue(seekBarControlEnum, progress);

    }


    private void actionSeekBar(BubbleSeekBar seekBar, int progress) {

        if (!(seekBar.getTag() instanceof SeekBarControlEnum)) {
            DebugLog.e("seekBar.getTag() is not instanceof SeekBarControlEnum, seekBar.getTag() = " + seekBar.getTag());
        }

        SeekBarControlEnum seekBarControlEnum = (SeekBarControlEnum) seekBar.getTag();

        sendServoValue(seekBarControlEnum, progress);

    }

    private void sendServoValue(SeekBarControlEnum seekBarControlEnum, int value) {

        IServoControl servoControl = ServoSingleton.INSTANCE.getServoControl();
        switch (seekBarControlEnum) {
            case minAngle:
                servoControl.setAngleAreaMin(value);
                break;
            case maxAngle:
                servoControl.setAngleAreaMax(value);
                break;
            case positionController:
                servoControl.setPosition(value);
                break;
            case angularVelocity:
                servoControl.setAngularVelocity(value);
                break;
            case feedbackTime:
                servoControl.setFeedbackTime_100ms(value);
                break;

        }

    }

    private final class LayoutSeekBarViewHolder {
        private final View sub;
        private final View add;
        private final BubbleSeekBar seekBar;

        public LayoutSeekBarViewHolder(@NonNull View container) {

            sub = container.findViewById(R.id.sub);
            add = container.findViewById(R.id.add);
            seekBar = (BubbleSeekBar) container.findViewById(R.id.seekBar);

            if (sub != null) {
                sub.setTag(container.getTag());
                sub.setOnClickListener(TestPositionFragment.this);
            }
            if (add != null) {
                add.setTag(container.getTag());
                add.setOnClickListener(TestPositionFragment.this);
            }
            if (seekBar != null) {
                seekBar.setTag(container.getTag());
                seekBar.setOnProgressChangedListener(TestPositionFragment.this);
                if (container.getTag() instanceof SeekBarControlEnum) {
                    int minRes = ((SeekBarControlEnum) container.getTag()).getMinValueRes();
                    int maxRes = ((SeekBarControlEnum) container.getTag()).getMaxValueRes();

                    int min = container.getContext().getResources().getInteger(minRes);
                    int max = container.getContext().getResources().getInteger(maxRes);

                    seekBar.getConfigBuilder()
                            .min(min)
                            .max(max)
                            .progress(min).build();
                }
            }
        }

        public View getSub() {
            return sub;
        }

        public View getAdd() {
            return add;
        }

        public BubbleSeekBar getSeekBar() {
            return seekBar;
        }
    }


    private enum SeekBarControlEnum {

        minAngle(R.id.layoutMinAngle, R.integer.angle_min, R.integer.angle_max),
        maxAngle(R.id.layoutMaxAngle,  R.integer.angle_min, R.integer.angle_max),
        positionController(R.id.layoutPositionController,  R.integer.angle_min, R.integer.angle_max),
        angularVelocity(R.id.layoutAngularVelocity,  R.integer.angular_velocity_min, R.integer.angular_velocity_max),
        feedbackTime(R.id.layoutTurn, R.integer.feedback_time_min, R.integer.feedback_time_max),

        ;
        final int containerViewRes;
        final int minValueRes;
        final int maxValueRes;

        private SeekBarControlEnum(int containerViewRes, int min, int max) {
            this.containerViewRes = containerViewRes;
            this.minValueRes = min;
            this.maxValueRes = max;
        }

        public int getContainerViewRes() {
            return containerViewRes;
        }

        public int getMinValueRes() {
            return minValueRes;
        }

        public int getMaxValueRes() {
            return maxValueRes;
        }

    }

}
